package ink.tiptop.learn.mapper.test;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import ink.tiptop.learn.pojo.po.test.TestUserBaseInfoPO;
import org.apache.ibatis.annotations.Mapper;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author zjf
 * @date 2020-08-16 14:54
 * 强大的条件构造器1
 */
@Mapper
public interface A_AbstractWrapperMapper extends BaseMapper<TestUserBaseInfoPO> {


    /**
     * 用于构建wrapper用的
     */
    Map<String, Object> wrapperMap = new HashMap<String, Object>() {{
        this.put("id", 1);
        this.put("name", "老王");
        this.put("age", null);
    }};
    /**
     * 用于构建wrapper用的
     */
    List<Object> wrapperList = new ArrayList<Object>() {{
        this.add(1);
        this.add(2);
        this.add(3);
    }};

    /**
     * 说明:
     * 1.以下出现的第一个入参boolean condition表示该条件是否加入最后生成的sql中      ***
     * 2.以下代码块内的多个方法均为从上往下补全个别boolean类型的入参,默认为true
     * 3.以下出现的泛型Param均为Wrapper的子类实例(均具有AbstractWrapper的所有方法)
     * 4.以下方法在入参中出现的R为泛型,在普通wrapper中是String,在LambdaWrapper中是函数(例:Entity::getId,Entity为实体类,getId为字段id的getMethod)
     * 5.以下方法入参中的R column均表示数据库字段,当R具体类型为String时则为数据库字段名(字段名是数据库关键字的自己用转义符包裹!)!而不是实体类数据字段名!!!,另当R具体类型为SFunction时项目runtime不支持eclipse自家的编译器!!!
     * 6.以下举例均为使用普通wrapper,入参为Map和List的均以json形式表现!
     * 7.使用中如果入参的Map或者List为空,则不会加入最后生成的sql中!!!
     * 警告:
     * 1.不支持以及不赞成在 RPC 调用中把 Wrapper 进行传输
     * 2.wrapper 很重
     * 3.传输 wrapper 可以类比为你的 controller 用 map 接收值(开发一时爽,维护火葬场)
     * 4.正确的 RPC 调用姿势是写一个 DTO 进行传输,被调用方再根据 DTO 执行相应的操作
     * 5.我们拒绝接受任何关于 RPC 传输 Wrapper 报错相关的 issue 甚至 pr
     */
    default void wrapper() {

    }

    /**
     * AbstractWrapper
     * 说明:
     * QueryWrapper(LambdaQueryWrapper) 和 UpdateWrapper(LambdaUpdateWrapper) 的父类
     * 用于生成 sql 的 where 条件, entity 属性也用于生成 sql 的 where 条件
     * 注意: entity 生成的 where 条件与 使用各个 api 生成的 where 条件没有任何关联行为
     */
    default void abstractWrapper() {

    }

    /**
     * AbstractWrapper使用方式1
     * <p>
     * allEq(Map<R, V> params)
     * allEq(Map<R, V> params, boolean null2IsNull)
     * allEq(boolean condition, Map<R, V> params, boolean null2IsNull)
     * <p>
     * 全部eq(或个别isNull)
     * 个别参数说明:
     * params : key为数据库字段名,value为字段值
     * null2IsNull : 为true则在map的value为null时调用 isNull 方法,为false时则忽略value为null的
     * <p>
     * 全部eq(或个别isNull)
     * <p>
     * wrapperMap-> {"id":1,"name":"老王","age":null}
     */
    default void abstractWrapper_1() {
        QueryWrapper<TestUserBaseInfoPO> wrapper = new QueryWrapper<>();
        // 1.输出SQL: id = 1 and name = '老王' and age is null
        wrapper.allEq(wrapperMap);
        // 2.输出SQL: id = 1 and name = '老王'
        wrapper.allEq(wrapperMap, false);
    }

    /**
     * AbstractWrapper使用方式2
     * <p>
     * allEq(BiPredicate<R, V> filter, Map<R, V> params)
     * allEq(BiPredicate<R, V> filter, Map<R, V> params, boolean null2IsNull)
     * allEq(boolean condition, BiPredicate<R, V> filter, Map<R, V> params, boolean null2IsNull)
     * <p>
     * 个别参数说明:
     * filter : 过滤函数,是否允许字段传入比对条件中
     * params 与 null2IsNull : 同上
     * <p>
     * wrapperMap-> {"id":1,"name":"老王","age":null}
     */
    default void abstractWrapper_2() {
        QueryWrapper<TestUserBaseInfoPO> wrapper = new QueryWrapper<>();
        //输出SQL: name = '老王' and age is null
        wrapper.allEq((k, v) -> k.contains("a"), wrapperMap);
        //输出SQL: name = '老王'
        wrapper.allEq((k, v) -> k.contains("a"), wrapperMap, false);
    }

    /**
     * AbstractWrapper使用方式3
     * <p>
     * eq(R column, Object val)
     * eq(boolean condition, R column, Object val)
     * <p>
     * 等于 =
     */
    default void abstractWrapper_3() {
        QueryWrapper<TestUserBaseInfoPO> wrapper = new QueryWrapper<>();
        // 输出SQL: name = '老王'
        wrapper.eq("name", "老王");
    }

    /**
     * AbstractWrapper使用方式4
     * <p>
     * ne(R column, Object val)
     * ne(boolean condition, R column, Object val)
     * <p>
     * 不等于 <>
     */
    default void abstractWrapper_4() {
        QueryWrapper<TestUserBaseInfoPO> wrapper = new QueryWrapper<>();
        // 输出SQL: name <> '老王'
        wrapper.ne("name", "老王");
    }

    /**
     * AbstractWrapper使用方式5
     * <p>
     * gt(R column, Object val)
     * gt(boolean condition, R column, Object val)
     * <p>
     * 大于 >
     */
    default void abstractWrapper_5() {
        QueryWrapper<TestUserBaseInfoPO> wrapper = new QueryWrapper<>();
        // 输出SQL: age > 18
        wrapper.gt("age", 18);
    }

    /**
     * AbstractWrapper使用方式6
     * <p>
     * ge(R column, Object val)
     * ge(boolean condition, R column, Object val)
     * <p>
     * 大于等于 >=
     */
    default void abstractWrapper_6() {
        QueryWrapper<TestUserBaseInfoPO> wrapper = new QueryWrapper<>();
        // 输出SQL: age >= 18
        wrapper.ge("age", 18);
    }

    /**
     * AbstractWrapper使用方式7
     * <p>
     * lt(R column, Object val)
     * lt(boolean condition, R column, Object val)
     * <p>
     * 小于 <
     */
    default void abstractWrapper_7() {
        QueryWrapper<TestUserBaseInfoPO> wrapper = new QueryWrapper<>();
        // 输出SQL: age < 18
        wrapper.lt("age", 18);
    }

    /**
     * AbstractWrapper使用方式8
     * <p>
     * le(R column, Object val)
     * le(boolean condition, R column, Object val)
     * <p>
     * 小于等于 <=
     */
    default void abstractWrapper_8() {
        QueryWrapper<TestUserBaseInfoPO> wrapper = new QueryWrapper<>();
        // 输出SQL: age <= 18
        wrapper.le("age", 18);
    }

    /**
     * AbstractWrapper使用方式9
     * <p>
     * between(R column, Object val1, Object val2)
     * between(boolean condition, R column, Object val1, Object val2)
     * <p>
     * BETWEEN 值1 AND 值2
     */
    default void abstractWrapper_9() {
        QueryWrapper<TestUserBaseInfoPO> wrapper = new QueryWrapper<>();
        // 输出SQL: age between 18 and 30
        wrapper.between("age", 18, 30);
    }

    /**
     * AbstractWrapper使用方式10
     * <p>
     * notBetween(R column, Object val1, Object val2)
     * notBetween(boolean condition, R column, Object val1, Object val2)
     * <p>
     * NOT BETWEEN 值1 AND 值2
     */
    default void abstractWrapper_10() {
        QueryWrapper<TestUserBaseInfoPO> wrapper = new QueryWrapper<>();
        // 输出SQL: age not between 18 and 30
        wrapper.notBetween("age", 18, 30);
    }

    /**
     * AbstractWrapper使用方式11
     * <p>
     * like(R column, Object val)
     * like(boolean condition, R column, Object val)
     * <p>
     * LIKE '%值%'
     */
    default void abstractWrapper_11() {
        QueryWrapper<TestUserBaseInfoPO> wrapper = new QueryWrapper<>();
        // 输出SQL: name like '%王%'
        wrapper.like("name", "王");
    }

    /**
     * AbstractWrapper使用方式12
     * <p>
     * notLike(R column, Object val)
     * notLike(boolean condition, R column, Object val)
     * <p>
     * NOT LIKE '%值%'
     */
    default void abstractWrapper_12() {
        QueryWrapper<TestUserBaseInfoPO> wrapper = new QueryWrapper<>();
        // 输出SQL: name not like '%王%'
        wrapper.notLike("name", "王");
    }

    /**
     * AbstractWrapper使用方式13
     * <p>
     * likeLeft(R column, Object val)
     * likeLeft(boolean condition, R column, Object val)
     * <p>
     * LIKE '%值'
     */
    default void abstractWrapper_13() {
        QueryWrapper<TestUserBaseInfoPO> wrapper = new QueryWrapper<>();
        // 输出SQL: name like '%王'
        wrapper.likeLeft("name", "王");
    }

    /**
     * AbstractWrapper使用方式14
     * <p>
     * likeRight(R column, Object val)
     * likeRight(boolean condition, R column, Object val)
     * <p>
     * LIKE '值%'
     */
    default void abstractWrapper_14() {
        QueryWrapper<TestUserBaseInfoPO> wrapper = new QueryWrapper<>();
        // 输出SQL: name like '王%'
        wrapper.likeLeft("name", "王");
    }

    /**
     * AbstractWrapper使用方式15
     * <p>
     * isNull(R column)
     * isNull(boolean condition, R column)
     * <p>
     * 字段 IS NULL
     */
    default void abstractWrapper_15() {
        QueryWrapper<TestUserBaseInfoPO> wrapper = new QueryWrapper<>();
        // 输出SQL: name is null
        wrapper.isNull("name");
    }

    /**
     * AbstractWrapper使用方式16
     * <p>
     * isNotNull(R column)
     * isNotNull(boolean condition, R column)
     * <p>
     * 字段 IS NULL
     */
    default void abstractWrapper_16() {
        QueryWrapper<TestUserBaseInfoPO> wrapper = new QueryWrapper<>();
        // 输出SQL: name is not null
        wrapper.isNotNull("name");
    }

    /**
     * AbstractWrapper使用方式17
     * <p>
     * in(R column, Collection<?> value)
     * in(boolean condition, R column, Collection<?> value)
     * <p>
     * 字段 IN (value.get(0), value.get(1), ...)
     * wrapperList:{1,2,3}
     */
    default void abstractWrapper_17() {
        QueryWrapper<TestUserBaseInfoPO> wrapper = new QueryWrapper<>();
        // 输出SQL: age in (1,2,3)
        wrapper.in("age", wrapperList);
    }

    /**
     * AbstractWrapper使用方式18
     * <p>
     * notIn(R column, Collection<?> value)
     * notIn(boolean condition, R column, Collection<?> value)
     * <p>
     * 字段 IN (value.get(0), value.get(1), ...)
     * wrapperList:{1,2,3}
     */
    default void abstractWrapper_18() {
        QueryWrapper<TestUserBaseInfoPO> wrapper = new QueryWrapper<>();
        // 输出SQL: age not in (1,2,3)
        wrapper.notIn("age", wrapperList);
    }

    /**
     * AbstractWrapper使用方式19
     * <p>
     * inSql(R column, String inValue)
     * inSql(boolean condition, R column, String inValue)
     * <p>
     * 字段 IN (value.get(0), value.get(1), ...)
     * wrapperList:{1,2,3}
     */
    default void abstractWrapper_19() {
        QueryWrapper<TestUserBaseInfoPO> wrapper = new QueryWrapper<>();
        // 输出SQL: age in (1,2,3)
        List<String> collect = wrapperList.stream().map(Object::toString).collect(Collectors.toList());
        wrapper.inSql("age", String.join(",", collect));

        // 输出SQL: age in (1,2,3)
        wrapper.inSql("age", "1,2,3");

        // 输出SQL: age in (select id from table where id < 3)
        wrapper.inSql("age", "select id from table where id < 3");
    }

    /**
     * AbstractWrapper使用方式20
     * <p>
     * notInSql(R column, String inValue)
     * notInSql(boolean condition, R column, String inValue)
     * <p>
     * 字段 NOT IN (value.get(0), value.get(1), ...)
     * wrapperList:{1,2,3}
     */
    default void abstractWrapper_20() {
        QueryWrapper<TestUserBaseInfoPO> wrapper = new QueryWrapper<>();
        // 输出SQL: age in (1,2,3)
        List<String> collect = wrapperList.stream().map(Object::toString).collect(Collectors.toList());
        wrapper.notInSql("age", String.join(",", collect));

        // 输出SQL: age not in (1,2,3)
        wrapper.notInSql("age", "1,2,3");

        // 输出SQL: age not in (select id from table where id < 3)
        wrapper.notInSql("age", "select id from table where id < 3");
    }

    /**
     * AbstractWrapper使用方式21
     * <p>
     * groupBy(R... columns)
     * groupBy(boolean condition, R... columns)
     * <p>
     * 分组：GROUP BY 字段, ...
     */
    default void abstractWrapper_21() {
        QueryWrapper<TestUserBaseInfoPO> wrapper = new QueryWrapper<>();
        // 输出SQL: group by id,name
        wrapper.groupBy("id", "name");
    }

    /**
     * AbstractWrapper使用方式22
     * <p>
     * orderByAsc(R... columns)
     * orderByAsc(boolean condition, R... columns)
     * <p>
     * 排序：ORDER BY 字段, ... ASC
     */
    default void abstractWrapper_22() {
        QueryWrapper<TestUserBaseInfoPO> wrapper = new QueryWrapper<>();
        // 输出SQL: order by id ASC,name ASC
        wrapper.orderByAsc("id", "name");
    }

    /**
     * AbstractWrapper使用方式23
     * <p>
     * orderByDesc(R... columns)
     * orderByDesc(boolean condition, R... columns)
     * <p>
     * 排序：ORDER BY 字段, ... DESC
     */
    default void abstractWrapper_23() {
        QueryWrapper<TestUserBaseInfoPO> wrapper = new QueryWrapper<>();
        // 输出SQL: order by id DESC,name DESC
        wrapper.orderByAsc("id", "name");
    }

    /**
     * AbstractWrapper使用方式24
     * <p>
     * orderBy(boolean condition, boolean isAsc, R... columns)
     * <p>
     * 排序：ORDER BY 字段, ...
     */
    default void abstractWrapper_24() {
        QueryWrapper<TestUserBaseInfoPO> wrapper = new QueryWrapper<>();
        // 输出SQL: order by id ASC,name ASC
        wrapper.orderBy(true, true, "id", "name");
    }

    /**
     * AbstractWrapper使用方式25
     * <p>
     * having(String sqlHaving, Object... params)
     * having(boolean condition, String sqlHaving, Object... params)
     * <p>
     * HAVING ( sql语句 )
     */
    default void abstractWrapper_25() {
        QueryWrapper<TestUserBaseInfoPO> wrapper = new QueryWrapper<>();
        // 输出SQL: having sum(age) > 10
        wrapper.having("sum(age) > 10");
        // 输出SQL: having sum(age) > 10
        wrapper.having("sum(age) > {0}", 11);
    }

    /**
     * AbstractWrapper使用方式26
     * <p>
     * func(Consumer<Children> consumer)
     * func(boolean condition, Consumer<Children> consumer)
     * <p>
     * func 方法(主要方便在出现if...else下调用不同方法能不断链)
     */
    default void abstractWrapper_26() {
        boolean cond = true;
        QueryWrapper<TestUserBaseInfoPO> wrapper = new QueryWrapper<>();
        // func(i -> if(true) {i.eq("id", 1)} else {i.ne("id", 1)})
        // 相当于一个可以外部控制条件选择sql拼接的方式
        QueryWrapper<TestUserBaseInfoPO> func = wrapper.func(i -> {
            if (cond) {
                i.eq("id", 1);
            } else {
                i.ne("id", 1);
            }
        });
    }

    /**
     * AbstractWrapper使用方式27
     * <p>
     * or()
     * or(boolean condition)
     * <p>
     * 拼接 OR
     * 注意事项:
     * 主动调用or表示紧接着下一个方法不是用and连接!(不调用or则默认为使用and连接)
     * <p>
     * or(Consumer<Param> consumer)
     * or(boolean condition, Consumer<Param> consumer)
     * OR 嵌套
     */
    default void abstractWrapper_27() {
        QueryWrapper<TestUserBaseInfoPO> wrapper = new QueryWrapper<>();
        // 输出SQL: id = 1 or name = '老王'
        wrapper.eq("id", 1).or().eq("name", "laowang");
        // 输出SQL: or (name = '李白' and status <> '活着')
        wrapper.or(i -> i.eq("name", "李白").ne("status", "活着"));
    }

    /**
     * AbstractWrapper使用方式28
     * <p>
     * and(Consumer<Param> consumer)
     * and(boolean condition, Consumer<Param> consumer)
     * <p>
     * AND 嵌套
     */
    default void abstractWrapper_28() {
        QueryWrapper<TestUserBaseInfoPO> wrapper = new QueryWrapper<>();
        // 输出SQL: and (name = '李白' and status <> '活着')
        wrapper.and(i -> i.eq("name", "李白").ne("status", "活着"));
    }

    /**
     * AbstractWrapper使用方式29
     * <p>
     * nested(Consumer<Param> consumer)
     * nested(boolean condition, Consumer<Param> consumer)
     * <p>
     * 正常嵌套 不带 AND 或者 OR
     */
    default void abstractWrapper_29() {
        QueryWrapper<TestUserBaseInfoPO> wrapper = new QueryWrapper<>();
        // 输出SQL: (name = '李白' and status <> '活着')
        wrapper.nested(i -> i.eq("name", "李白").ne("status", "活着"));
    }

    /**
     * AbstractWrapper使用方式30
     * <p>
     * apply(String applySql, Object... params)
     * apply(boolean condition, String applySql, Object... params)
     * <p>
     * 拼接 sql
     * 注意事项:
     * 该方法可用于数据库函数 动态入参的params对应前面applySql内部的{index}部分.这样是不会有sql注入风险的,反之会有!
     */
    default void abstractWrapper_30() {
        QueryWrapper<TestUserBaseInfoPO> wrapper = new QueryWrapper<>();
        // 输出SQL: id = 1
        wrapper.apply("id = 1");
        // 输出SQL: date_format(dateColumn,'%Y-%m-%d') = '2008-08-08'")
        wrapper.apply("date_format(dateColumn,'%Y-%m-%d') = '2008-08-08'");
        // 输出SQL: date_format(dateColumn,'%Y-%m-%d') = '2008-08-08'")
        wrapper.apply("date_format(dateColumn,'%Y-%m-%d') = {0}", "2008-08-08");
    }

    /**
     * AbstractWrapper使用方式31
     * <p>
     * last(String lastSql)
     * last(boolean condition, String lastSql)
     * <p>
     * 无视优化规则直接拼接到 sql 的最后
     * 注意事项:
     * 只能调用一次,多次调用以最后一次为准 有sql注入的风险,请谨慎使用
     */
    default void abstractWrapper_31() {
        QueryWrapper<TestUserBaseInfoPO> wrapper = new QueryWrapper<>();
        // 输出SQL: limit 1
        wrapper.last("limit 1");
    }

    /**
     * AbstractWrapper使用方式32
     * <p>
     * exists(String existsSql)
     * exists(boolean condition, String existsSql)
     * <p>
     * 拼接 EXISTS ( sql语句 ) 用在where后,返回true活着false
     */
    default void abstractWrapper_32() {
        QueryWrapper<TestUserBaseInfoPO> wrapper = new QueryWrapper<>();
        // 输出SQL: exists (select id from table where age = 1)
        wrapper.exists("select id from table where age = 1");
    }

    /**
     * AbstractWrapper使用方式33
     * <p>
     * notExists(String notExistsSql)
     * notExists(boolean condition, String notExistsSql)
     * <p>
     * 拼接 NOT EXISTS ( sql语句 )
     */
    default void abstractWrapper_33() {
        QueryWrapper<TestUserBaseInfoPO> wrapper = new QueryWrapper<>();
        // 输出SQL: not exists (select id from table where age = 1)
        wrapper.notExists("select id from table where age = 1");
    }

}
